#include "./gattclient.h"
#include "../main.h"
#include "./gap.h"
#include "./links.h"
#include "ble/BLE.h"

GattClientDemo gattclient;

GattClientDemo::GattClientDemo() {}
GattClientDemo::~GattClientDemo() {
  if (!_client) {
    return;
  }
  _client->onServiceDiscoveryTermination(nullptr);
  _client->onDataRead(nullptr);
  _client->onDataWritten(nullptr);
}

void GattClientDemo::init(ble::GattClient &gattclient) {
  _client = &gattclient;
  _client->onServiceDiscoveryTermination(
      makeFunctionPointer(this, &Self::when_service_discovery_ends));
  _client->onDataRead(
      makeFunctionPointer(this, &Self::when_characteristic_read));
  _client->onDataWritten(
      makeFunctionPointer(this, &Self::when_characteristic_written));
  _client->setEventHandler(this);
}

void GattClientDemo::start_discovery(
    ble::connection_handle_t connection_handle) {
  ble_error_t error = _client->launchServiceDiscovery(
      connection_handle,
      makeFunctionPointer(this, &Self::when_service_discovered),
      makeFunctionPointer(this, &Self::when_characteristic_discovered),
      UNMP_SERVICE_UUID);
  if (error) {
    printf("Error %u returned by _client->launchServiceDiscovery.\r\n", error);
    return;
  }

  printf("Client process started: initiate service discovery.\r\n");
}

void GattClientDemo::onAttMtuChange(ble::connection_handle_t connection_handle,
                                    uint16_t attMtuSize) {
  printf("ATT_MTU changed on the connection %d to a new value of %d.\r\n",
         connection_handle, attMtuSize);
}

void GattClientDemo::when_service_discovered(
    const DiscoveredService *discovered_service) {
  printf("Service discovered.\r\n");
}

void GattClientDemo::when_characteristic_discovered(
    const DiscoveredCharacteristic *discovered_characteristic) {
  auto connection_handle = discovered_characteristic->getConnectionHandle();
  BleLinks::Link *link = blelinks.get_link_by_handle(connection_handle);
  MBED_ASSERT(link != nullptr);

  if (discovered_characteristic->getUUID() == UNMP_ID_CHAR_UUID) {
    printf("find UNMP_ID_CHAR_UUID\r\n");
    link->id_handle = discovered_characteristic->getValueHandle();
    return;
  }
  if (discovered_characteristic->getUUID() == UNMP_RX_CHAR_UUID) {
    printf("find UNMP_RX_CHAR_UUID\r\n");
    link->rx_handle = discovered_characteristic->getValueHandle();
    return;
  }
}

void GattClientDemo::when_service_discovery_ends(
    ble::connection_handle_t connection_handle) {
  printf("All services and characteristics discovered, process them.\r\n");

  BleLinks::Link *link = blelinks.get_link_by_handle(connection_handle);
  MBED_ASSERT(link != nullptr);
  if (link->id_handle == GattAttribute::INVALID_HANDLE ||
      link->rx_handle == GattAttribute::INVALID_HANDLE) {
    gap.disconnect(connection_handle,
                   ble::local_disconnection_reason_t::AUTHENTICATION_FAILURE);
    return;
  }
  event_queue.call([this, connection_handle] {
    _client->negotiateAttMtu(connection_handle);
  });
  event_queue.call([this, connection_handle, link] {
    _client->read(connection_handle, link->id_handle, 0);
  });

  //_client->write(ble::GattClient::GATT_OP_WRITE_REQ, connection_handle,
  //               link->rx_handle, 8, config.device_id);
}

void GattClientDemo::when_characteristic_read(
    const GattReadCallbackParams *event) {
  BleLinks::Link *link = blelinks.get_link_by_handle(event->connHandle);
  MBED_ASSERT(link != nullptr);
  if (link->id_handle == event->handle) {
    printf("unmp id: ");
    for (size_t i = 0; i < event->len; i++) {
      printf("0x%02X ", event->data[i]);
    }
    printf(".\r\n");
  }
}
void GattClientDemo::when_characteristic_written(
    const GattWriteCallbackParams *event) {
  printf("Characteristic value at %u written.\r\n", event->handle);
}
